package de.dnb.gnd.parser.line;

import java.util.Collection;

import de.dnb.basics.applicationComponents.RangeCheckUtils;
import de.dnb.basics.applicationComponents.Triplett;
import de.dnb.gnd.exceptions.IllFormattedLineException;
import de.dnb.gnd.parser.Format;
import de.dnb.gnd.parser.Subfield;
import de.dnb.gnd.parser.tag.BibTagDB;
import de.dnb.gnd.parser.tag.GNDTagDB;
import de.dnb.gnd.parser.tag.Tag;
import de.dnb.gnd.parser.tag.TagDB;

/**
 * Hilfsklasse, die das Parsen von Zeilen erleichtert.
 * 
 * @author baumann
 *
 */
public final class LineParser {

	private LineParser() {
		super();
	}

	/**
	 * Parst eine durch tag und contentStr gegebene Zeile.
	 * 
	 * @param tag		nicht null.
	 * @param format		pica3 oder pica+. Wird durch die Form von Tag
	 * 						erkannt und erleichtert das Parsen.
	 * @param contentStr	nicht null nicht leer.
	 * @param ignoreMARC	Überlese beim Parsen von Pica+-Daten die Felder, 
	 * 						die in MARC21 üblich sind, die aber nicht zum 
	 * 						Pica-Format gehören.
	 * @return				Eine Zeile.
	 * @throws IllFormattedLineException
	 * 						Wenn contentStr falsch formatiert.
	 */
	public static Line parse(
		final Tag tag,
		final Format format,
		final String contentStr,
		final boolean ignoreMARC) throws IllFormattedLineException {
		LineFactory factory = tag.getLineFactory();
		try {
			factory.load(format, contentStr, ignoreMARC);
		} catch (IllFormattedLineException e) {
			throw e;
		}
		return factory.createLine();
	}

	/**
	 * Wandelt eine durch tag und durch subfields gegebene Liste in eine
	 * Zeile um.
	 * 
	 * @param tag		nicht null.
	 * @param subfields		nicht null, nicht leer.
	 * @return				eine Zeile
	 * @throws IllFormattedLineException
	 * 						Wenn die subfields nicht zum Tag und zur 
	 * 						Wiederholbarkeit passen.
	 */
	public static
		Line
		parse(final Tag tag, final Collection<Subfield> subfields)
			throws IllFormattedLineException {
		LineFactory factory = tag.getLineFactory();
		factory.load(subfields);
		return factory.createLine();
	}

	/**
	 * Hilfsmethode, die eine vollständige Zeile parst. Da der Tag als String
	 * (Präfix der Zeile) vorliegt, muss noch die DB angegeben werden, in
	 * der der Tag gesucht werden muss.
	 * 
	 * @param lineStr		nicht null, nicht leer.
	 * @param tagDB			nicht null.
	 * @param ignoreMARC 	Überlese beim Parsen von Pica+-Daten die Felder, 
	 * 						die in MARC21 üblich sind, die aber nicht zum 
	 * 						Pica-Format gehören.
	 * @return				gültige Zeile oder null, wenn keine mit
	 * 						bekanntem Tag beginnende Zeile vorliegt.
	 * @throws IllFormattedLineException
	 * 						falsch formatierte Zeile.
	 */
	public static Line parse(
		final String lineStr,
		final TagDB tagDB,
		final boolean ignoreMARC) throws IllFormattedLineException {
		RangeCheckUtils.assertStringParamNotNullOrEmpty("lineStr", lineStr);
		RangeCheckUtils.assertReferenceParamNotNull("tagDB", tagDB);
		Triplett<Tag, String, String> triplett = tagDB.parseTag(lineStr);
		if (triplett != null) {
			Tag tag = triplett.first;
			String content = triplett.third;
			Format format;
			if (triplett.second.equals(tag.pica3)) {
				format = Format.PICA3;
			} else {
				format = Format.PICA_PLUS;
			}
			try {
				return parse(tag, format, content, ignoreMARC);
			} catch (IllFormattedLineException e) {
				throw e;
			}
		}
		return null;
	}

	/**
	 * Hilfsmethode, die eine vollständige GND-Zeile im Pica3-Format parst. 
	 * 
	 * @param lineStr		nicht null, nicht leer.
	 *
	 * @return				gültige Zeile oder null, wenn keine mit
	 * 						bekanntem Tag beginnende Zeile vorliegt.
	 * @throws IllFormattedLineException
	 * 						falsch formatierte Zeile.
	 */
	public static Line parseGND(final String lineStr)
		throws IllFormattedLineException {
		RangeCheckUtils.assertStringParamNotNullOrEmpty("lineStr", lineStr);
		return parse(lineStr, GNDTagDB.getDB(), false);
	}

	/**
	 * @param args
	 * @throws IllFormattedLineException 
	 */
	public static void main(String[] args) throws IllFormattedLineException {

		Line line =
			parse(
				"028A $9101386281$7Tp1$Vpiz$Agnd$0101386281$E1895$aVöltzer$dFriedrich",
				BibTagDB.getDB(), true);
		System.out.println(line);

	}

	public static LineFactory getFactory(String tagStr, TagDB tagDB) {
		RangeCheckUtils.assertStringParamNotNullOrEmpty("tagStr", tagStr);
		RangeCheckUtils.assertReferenceParamNotNull("tagDB", tagDB);
		Tag tag = tagDB.findTag(tagStr);
		return tag.getLineFactory();
	}

}
